#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/event_groups.h"
#include "esp_system.h"
#include "esp_wifi.h"
#include "esp_event.h"
#include "esp_log.h"
#include "esp_attr.h"
#include "nvs_flash.h"

#include "blufi_security.h"
#include "blufi.h"
#include "wifi.h"

#include "esp_blufi.h"
#include "esp_bt.h"
#include "esp_bt_device.h"
#include "esp_blufi_api.h"
#include "esp_bt_defs.h"
#include "esp_gap_ble_api.h"
#include "esp_bt_main.h"

_Cur_ble_client_inf cur_blec_inf;

const char* TAG_BLEFI_EVENT = "BLEFI_EVENT";

//服务UUID
static uint8_t service_uuid128[32] = {
    /* LSB <--------------------------------------------------------------------------------> MSB */
    //first uuid, 16bit, [12],[13] is the value
    0xfb,
    0x34,
    0x9b,
    0x5f,
    0x80,
    0x00,
    0x00,
    0x80,
    0x00,
    0x10,
    0x00,
    0x00,
    0xFF,
    0xFF,
    0x00,
    0x00,
};

/** 广播参数 **/
static esp_ble_adv_params_t
    adv_params = {
        .adv_int_min = 0x100,                  //无定向广播和低占空比定向广播的最小广播间隔。取值范围:0x0020 ~ 0x4000。默认值:N = 0x0800(1.28秒)。TIME= N * 0.625 msec。时间范围:20 ms ~ 10.24秒
        .adv_int_max = 0x100,                  //无定向广播和低占空比定向广播的最大广播间隔。取值范围:0x0020 ~ 0x4000。默认值:N = 0x0800(1.28秒)。TIME= N * 0.625 msec。时间范围:20毫秒~ 10.24秒
        .adv_type = ADV_TYPE_IND,              //广播类型
        .own_addr_type = BLE_ADDR_TYPE_PUBLIC, //所有者蓝牙设备地址类型
        //.peer_addr            =                               //对端设备蓝牙设备地址
        //.peer_addr_type       =                               //对端设备蓝牙设备地址类型,只支持公网地址类型和随机地址类型
        .channel_map = ADV_CHNL_ALL,                            //广告通道映射
        .adv_filter_policy = ADV_FILTER_ALLOW_SCAN_ANY_CON_ANY, //广告过滤政策
};

/** adv蓝牙广播数据 **/
static esp_ble_adv_data_t adv_data = {
    .set_scan_rsp = false,             //是否将此广播数据设置为扫描响应
    .include_name = true,              //广播数据是否包括设备名称
    .include_txpower = true,           //广播数据包括TX功率
    .min_interval = 0x0006,            //从连接的最小间隔,时间= min_interval * 1.25毫秒
    .max_interval = 0x0010,            //从连接最大间隔,时间= max_interval * 1.25 msec
    .appearance = 0x00,                //设备外观
    .manufacturer_len = 0,             //制造商数据长度
    .p_manufacturer_data = NULL,       //制造商的数据指针
    .service_data_len = 0,             //服务数据长度
    .p_service_data = NULL,            //服务数据指针
    .service_uuid_len = 16,            //服务uuid长度
    .p_service_uuid = service_uuid128, //服务uuid指针
    .flag = 0x6,                       //发现模式的广播标志,请参见BLE_ADV_DATA_FLAG
};

/** 广播事件 **/
static void gap_event_handler(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *param)
{
    switch (event)
    {
    case ESP_GAP_BLE_ADV_DATA_SET_COMPLETE_EVT:
        esp_ble_gap_start_advertising(&adv_params); //开始广播
        break;
    default:
        break;
    }
}

static void blufi_event_callback(esp_blufi_cb_event_t event, esp_blufi_cb_param_t *param)
{
    BLUFI_INFO("BLUFI EVENT: %d", event);

    switch (event)
    {
        //BLUFI初始化完成
    case ESP_BLUFI_EVENT_INIT_FINISH:
        BLUFI_INFO("BLUFI 初始化完成\n");
        BLUFI_INFO("开始蓝牙广播");
        esp_ble_gap_set_device_name(BLUFI_DEVICE_NAME);
        esp_ble_gap_config_adv_data(&adv_data);
        break;
        //BLUFI卸载完成
    case ESP_BLUFI_EVENT_DEINIT_FINISH:
        BLUFI_INFO("BLUFI 卸载完成\n");
        break;
        //BLUFI有设备连接
    case ESP_BLUFI_EVENT_BLE_CONNECT:
        BLUFI_INFO("BLUFI有设备连接成功\n");
        cur_blec_inf.ble_is_connected = true;
        cur_blec_inf.server_if = param->connect.server_if;
        cur_blec_inf.conn_id = param->connect.conn_id;
        esp_ble_gap_stop_advertising(); //停止广播
        blufi_security_init();          //加密
        break;
        //BLUFI设备断开连接
    case ESP_BLUFI_EVENT_BLE_DISCONNECT:
        BLUFI_INFO("BLUFI 蓝牙设备断开连接\n");
        cur_blec_inf.ble_is_connected = false;
        blufi_security_deinit();                    //卸载加密
        esp_ble_gap_start_advertising(&adv_params); //开始广播
        break;
        //BLUFI设置wifi模式
    case ESP_BLUFI_EVENT_SET_WIFI_OPMODE:
        BLUFI_INFO("BLUFI 设置WiFi模式:%d\n", param->wifi_mode.op_mode);
        ESP_ERROR_CHECK(esp_wifi_set_mode(param->wifi_mode.op_mode));
        break;
        //BLUFI请求重新连接WiFi
    case ESP_BLUFI_EVENT_REQ_CONNECT_TO_AP:
        BLUFI_INFO("BLUFI 请求wifi连接到AP\n");
        /* 当设备已经连接到这个wifi时,没有wifi回调,所以连接之前断开wifi。*/
        esp_wifi_disconnect();
        esp_wifi_connect();
        break;
        //BLUFI请求断开WiFi连接
    case ESP_BLUFI_EVENT_REQ_DISCONNECT_FROM_AP:
        BLUFI_INFO("BLUFI 请求从AP断开wifi连接\n");
        esp_wifi_disconnect();
        break;
        //BLUFI报告错误
    case ESP_BLUFI_EVENT_REPORT_ERROR:
        BLUFI_ERROR("BLUFI 报告错误,错误代码:%d\n", param->report_error.state);
        esp_blufi_send_error_info(param->report_error.state);
        break;
        //BLUFI获取wifi状态
    case ESP_BLUFI_EVENT_GET_WIFI_STATUS:
    {
        wifi_mode_t mode;
        esp_blufi_extra_info_t info;

        esp_wifi_get_mode(&mode);

        if (cur_wifi_info.isConnected)
        {
            memset(&info, 0, sizeof(esp_blufi_extra_info_t));
            memcpy(info.sta_bssid, cur_wifi_info.bssid, 6);
            info.sta_bssid_set = true;
            info.sta_ssid = cur_wifi_info.ssid;
            info.sta_ssid_len = cur_wifi_info.ssid_len;
            esp_blufi_send_wifi_conn_report(mode, ESP_BLUFI_STA_CONN_SUCCESS, 0, &info);
        }
        else
        {
            esp_blufi_send_wifi_conn_report(mode, ESP_BLUFI_STA_CONN_FAIL, 0, NULL);
        }
        BLUFI_INFO("BLUFI 从AP获取wifi状态\n");

        break;
    }
        //设备请求断开连接
    case ESP_BLUFI_EVENT_RECV_SLAVE_DISCONNECT_BLE:
        BLUFI_INFO("BLUFI 关闭设备gatt连接");
        esp_blufi_close(cur_blec_inf.server_if, cur_blec_inf.conn_id);
        break;
        //什么玩意,不懂
    case ESP_BLUFI_EVENT_DEAUTHENTICATE_STA:
        /* TODO */ //什么玩意
        break;
        //BLUFI接收WIFI MAC地址
    case ESP_BLUFI_EVENT_RECV_STA_BSSID:
        memcpy(sta_config.sta.bssid, param->sta_bssid.bssid, 6);
        sta_config.sta.bssid_set = 1;
        esp_wifi_set_config(WIFI_IF_STA, &sta_config);
        BLUFI_INFO("BLUFI 接收WIFI MAC地址: %s\n", sta_config.sta.ssid);
        break;
        //BLUFI接收WIFI SSID
    case ESP_BLUFI_EVENT_RECV_STA_SSID:
        strncpy((char *)sta_config.sta.ssid, (char *)param->sta_ssid.ssid, param->sta_ssid.ssid_len);
        sta_config.sta.ssid[param->sta_ssid.ssid_len] = '\0';

        esp_wifi_set_config(WIFI_IF_STA, &sta_config);
        BLUFI_INFO("BLUFI 接收WIFI SSID: %s\n", sta_config.sta.ssid);
        break;
        //BLUFI接收WIFI 密码
    case ESP_BLUFI_EVENT_RECV_STA_PASSWD:
        strncpy((char *)sta_config.sta.password, (char *)param->sta_passwd.passwd, param->sta_passwd.passwd_len);
        sta_config.sta.password[param->sta_passwd.passwd_len] = '\0';
        strncpy((char *)cur_wifi_info.password, (char *)param->sta_passwd.passwd, param->sta_passwd.passwd_len);
        cur_wifi_info.password[param->sta_passwd.passwd_len] = '\0';

        esp_wifi_set_config(WIFI_IF_STA, &sta_config);
        BLUFI_INFO("BLUFI 接收WIFI 密码: %s\n", sta_config.sta.password);
        break;
    case ESP_BLUFI_EVENT_RECV_SOFTAP_SSID:
        BLUFI_INFO("暂无此功能");
        break;
    case ESP_BLUFI_EVENT_RECV_SOFTAP_PASSWD:
        BLUFI_INFO("暂无此功能");
        break;
    case ESP_BLUFI_EVENT_RECV_SOFTAP_MAX_CONN_NUM:
        BLUFI_INFO("暂无此功能");
        break;
    case ESP_BLUFI_EVENT_RECV_SOFTAP_AUTH_MODE:
        BLUFI_INFO("暂无此功能");
        break;
    case ESP_BLUFI_EVENT_RECV_SOFTAP_CHANNEL:
        BLUFI_INFO("暂无此功能");
        break;
        //获取附近WIFI
    case ESP_BLUFI_EVENT_GET_WIFI_LIST:
    {
        wifi_scan_start();
        xEventGroupClearBits(wifi_event_group, WIFI_SCAN_FINISH_BIT);
        xEventGroupWaitBits(
            wifi_event_group,                     // 事件组
            WIFI_SCAN_FINISH_BIT | WIFI_FAIL_BIT, // 等待的位
            pdTRUE,                               //运行前是否清空
            pdFALSE,                              // 是否等待所有位被置为
            10000 / portTICK_PERIOD_MS);                       // 设置最长等待时间

        if ((xEventGroupGetBits(wifi_event_group) ) == WIFI_FAIL_BIT)
        {
            ESP_LOGI(TAG_WIFI,"WiFi扫描失败");
            esp_blufi_send_wifi_list(cur_wifi_list.apCount, NULL);
            free(cur_wifi_list.ap_list);
            break;
        }
        
        esp_blufi_ap_record_t * blufi_ap_list = (esp_blufi_ap_record_t *)malloc(cur_wifi_list.apCount * sizeof(esp_blufi_ap_record_t));
        if (!blufi_ap_list) {
            free(blufi_ap_list);
            free(cur_wifi_list.ap_list);
            BLUFI_ERROR("内存开辟失败,blufi_ap_list为空");
            break;
        };




        for (int i = 0; i < cur_wifi_list.apCount; ++i)
        {
            blufi_ap_list[i].rssi = cur_wifi_list.ap_list[i].rssi;
            memcpy(blufi_ap_list[i].ssid, cur_wifi_list.ap_list[i].ssid, sizeof(cur_wifi_list.ap_list[i].ssid));
        }

        if (cur_blec_inf.ble_is_connected == true) {
            esp_blufi_send_wifi_list(cur_wifi_list.apCount, blufi_ap_list);
        } else {
            BLUFI_INFO("蓝牙未连接\n");
        }

        free(blufi_ap_list);
        free(cur_wifi_list.ap_list);
        break;
    }
    case ESP_BLUFI_EVENT_RECV_CUSTOM_DATA:
    {
        // char *temp = (char*)malloc(sizeof(char)*(param->custom_data.data_len));
        // strncpy(temp,(char*)param->custom_data.data,param->custom_data.data_len);
        // printf("%ld\r\n",param->custom_data.data_len);
        // printf("%d\r\n",strlen(temp));
        // ESP_LOGI("TAG","TAG1");
        // for(int i = 0;i<param->custom_data.data_len;i++){
            // ESP_LOGI("TAG","TAG2");
            // temp[i] = (char*)param->custom_data.data;
            // printf("%s\r\n",(char*)param->custom_data.data);
// ESP_LOGI("TAG","TAG3");
            // param->custom_data.data++;
        // }
        // ESP_LOGI("TAG","TAG4");
        // ESP_LOGI("awa","DATA:%s",temp);
        // for(int i = 0;i<param->custom_data.data_len-4;i++){
        // free(temp);

        // }
        nvs_flash_erase();
        vTaskDelay(2000 / portTICK_PERIOD_MS);
        esp_restart();
        break;
    }
    case ESP_BLUFI_EVENT_RECV_USERNAME:
        BLUFI_INFO("暂无此功能");
        break;
    case ESP_BLUFI_EVENT_RECV_CA_CERT:
        BLUFI_INFO("暂无此功能");
        break;
    case ESP_BLUFI_EVENT_RECV_CLIENT_CERT:
        BLUFI_INFO("暂无此功能");
        break;
    case ESP_BLUFI_EVENT_RECV_SERVER_CERT:
        BLUFI_INFO("暂无此功能");
        break;
    case ESP_BLUFI_EVENT_RECV_CLIENT_PRIV_KEY:
        BLUFI_INFO("暂无此功能");
        break;
    case ESP_BLUFI_EVENT_RECV_SERVER_PRIV_KEY:
        BLUFI_INFO("暂无此功能");
        break;
    default:
        break;
    }
}

static esp_blufi_callbacks_t blufi_callbacks = {
    .event_cb = blufi_event_callback,
    .negotiate_data_handler = blufi_dh_negotiate_data_handler,
    .encrypt_func = blufi_aes_encrypt,
    .decrypt_func = blufi_aes_decrypt,
    .checksum_func = blufi_crc_checksum,
};


void init_blufi()
{
    esp_err_t ret;
    ESP_ERROR_CHECK(esp_bt_controller_mem_release(ESP_BT_MODE_CLASSIC_BT));

    esp_bt_controller_config_t bt_cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT();
    ret = esp_bt_controller_init(&bt_cfg);
    if (ret)
    {
        BLUFI_ERROR("%s 初始化bt控制器失败: %s\n", __func__, esp_err_to_name(ret));
    }

    ret = esp_bt_controller_enable(ESP_BT_MODE_BLE);
    if (ret)
    {
        BLUFI_ERROR("%s bt控制器启动失败: %s\n", __func__, esp_err_to_name(ret));
        return;
    }

    ret = esp_bluedroid_init();
    if (ret)
    {
        BLUFI_ERROR("%s 初始化蓝牙失败: %s\n", __func__, esp_err_to_name(ret));
        return;
    }

    ret = esp_bluedroid_enable();
    if (ret)
    {
        BLUFI_ERROR("%s 启动蓝牙失败: %s\n", __func__, esp_err_to_name(ret));
        return;
    }

    BLUFI_INFO("蓝牙地址:" ESP_BD_ADDR_STR "\n", ESP_BD_ADDR_HEX(esp_bt_dev_get_address()));
    BLUFI_INFO("BLUFI 版本 %04x\n", esp_blufi_get_version());
    // uint8_t awa = "waw";
    // blufi_aes_encrypt("123456",awa,strlen((uint8_t)awa));
     ret = esp_blufi_register_callbacks(&blufi_callbacks);
    if (ret)
    {
        BLUFI_ERROR("%s blufi注册失败,错误码 = %x\n", __func__, ret);
        return;
    }

    ret = esp_ble_gap_register_callback(gap_event_handler);
    if (ret)
    {
        BLUFI_ERROR("%s 蓝牙广播注册失败,错误码 = %x\n", __func__, ret);
        return;
    }

   

    esp_blufi_profile_init();
    cur_blec_inf.blufi_is_init=true;
}

void deinit_blufi(){
    esp_blufi_deinit();
}